home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / libs / unixlib.lha / unix / src / _main.c < prev    next >
C/C++ Source or Header  |  1996-11-09  |  12KB  |  484 lines

  1.  
  2. #include "amiga.h"
  3. #include "signals.h"
  4. #include "fifofd.h"
  5. #include "timers.h"
  6. #include "amigados.h"
  7. #include <exec/execbase.h>
  8. #include <dos/var.h>
  9. #include <workbench/startup.h>
  10. #include <proto/timer.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <sys/time.h>
  15. #include <pwd.h>
  16. #include <ios1.h>
  17.  
  18. struct Process *_us;
  19. struct timeinfo *_odd_timer;
  20. ULONG _odd_sig;
  21. long _startup_time;
  22. long _stack_size;
  23. struct Library *TimerBase;
  24.  
  25. static char *empty_env = 0;     /* A default empty environment */
  26. char **environ;                 /* Unix style environment variable list */
  27. char *_system_name;
  28.  
  29. extern struct ExecBase *SysBase;
  30. extern struct passwd _amiga_user;
  31. extern struct UFB *__ufbs;
  32. int main(int argc, char **argv, char **envp);
  33. extern void _fail(char *format,...);
  34.  
  35. static void nomem(void)
  36. {
  37.     _fail("No memory");
  38. }
  39.  
  40. static void *_xmalloc(unsigned n)
  41. {
  42.     void *p = malloc(n);
  43.  
  44.     if (!p)
  45.     nomem();
  46.  
  47.     return p;
  48. }
  49.  
  50. static void *_xrealloc(void *p, unsigned n)
  51. {
  52.     void *p2 = realloc(p, n);
  53.  
  54.     if (!p2)
  55.     nomem();
  56.  
  57.     return p2;
  58. }
  59.  
  60. static char *safe_copystr(char *str)
  61. {
  62.     char *new;
  63.  
  64.     if (!str)
  65.     str = "";
  66.     new = malloc(strlen(str) + 1);
  67.     if (!new)
  68.     return 0;
  69.     return strcpy(new, str);
  70. }
  71.  
  72. void make_environ(void)
  73. /* Effect: Builds a UNIX style environ variable from the AmigaDOS environment.
  74.  */
  75. {
  76.     int env_count = 0;
  77.     long env_len = 0;
  78.     struct LocalVar *scan_env;
  79.     char **new_environ, *env_text;
  80.  
  81.     for (scan_env = (struct LocalVar *) _us->pr_LocalVars.mlh_Head;
  82.      scan_env->lv_Node.ln_Succ;
  83.      scan_env = (struct LocalVar *) scan_env->lv_Node.ln_Succ) {
  84.  
  85.     if (scan_env->lv_Node.ln_Type == LV_VAR &&
  86.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR))) {
  87.         /* We only handle local text variables */
  88.         env_count++;
  89.         env_len += 2 + strlen(scan_env->lv_Node.ln_Name) + scan_env->lv_Len;
  90.     }
  91.     }
  92.     new_environ = environ = (char **)_xmalloc(sizeof(char *) * (1 + env_count) +
  93.                            env_len);
  94.     env_text = (char *) (environ + (1 + env_count));
  95.     if (!environ)
  96.     environ = &empty_env;
  97.     else {
  98.     for (scan_env = (struct LocalVar *) _us->pr_LocalVars.mlh_Head;
  99.          scan_env->lv_Node.ln_Succ;
  100.          scan_env = (struct LocalVar *) scan_env->lv_Node.ln_Succ) {
  101.  
  102.         if (scan_env->lv_Node.ln_Type == LV_VAR &&
  103.         !(scan_env->lv_Flags & (GVF_GLOBAL_ONLY | GVF_BINARY_VAR))) {
  104.         /* We only handle local text variables */
  105.         char *env_name = scan_env->lv_Node.ln_Name;
  106.         int env_len = scan_env->lv_Len;
  107.  
  108.         *new_environ++ = env_text;
  109.         while (*env_name)
  110.             *env_text++ = *env_name++;
  111.         *env_text++ = '=';
  112.         env_name = scan_env->lv_Value;
  113.         while (env_len--)
  114.             *env_text++ = *env_name++;
  115.         *env_text++ = '\0';
  116.         }
  117.     }
  118.     *new_environ = 0;
  119.     }
  120. }
  121.  
  122. /*  _main routine.
  123.  *  Hides the differences between wb & cli.
  124.  *  Provides a unix-like environment (including coomand-line parsing &
  125.  *  wildcard expansion)
  126.  */
  127.  
  128. #define DEFPATLEN 256
  129. #define NAMELEN 1024
  130.  
  131. struct args {
  132.     int size;
  133.     int argc;
  134.     char **argv;
  135. };
  136.  
  137. static void make_argv(struct args *args, int argc)
  138. {
  139.     args->size = argc;
  140.     args->argc = 0;
  141.     args->argv = _xmalloc(sizeof(char *) * argc);
  142. }
  143.  
  144. static int safe_add_arg(struct args *args, char *argument, int copy)
  145. {
  146.     char *arg_copy;
  147.  
  148.     if (copy)
  149.     arg_copy = safe_copystr(argument);
  150.     else
  151.     arg_copy = argument;
  152.  
  153.     if (!arg_copy)
  154.     return 0;
  155.  
  156.     if (args->argc >= args->size) {
  157.     /* Make argv bigger */
  158.     if (args->size * 2 < args->size + 16)
  159.         args->size += 16;
  160.     else
  161.         args->size *= 2;
  162.  
  163.     args->argv = realloc(args->argv, sizeof(char *) * args->size);
  164.  
  165.     if (!args->argv)
  166.         return 0;
  167.     }
  168.     args->argv[args->argc++] = arg_copy;
  169.     return 1;
  170. }
  171.  
  172. static void add_arg(struct args *args, char *argument, int copy)
  173. {
  174.     if (!safe_add_arg(args, argument, copy))
  175.     nomem();
  176. }
  177.  
  178. static void concat_args(struct args *args, struct args *add)
  179. {
  180.     if (args->argc + add->argc > args->size) {
  181.     args->size = (args->argc + add->argc) * 2;
  182.     args->argv = _xrealloc(args->argv, sizeof(char *) * args->size);
  183.     }
  184.     memcpy(args->argv + args->argc, add->argv, add->argc * sizeof(char *));
  185.     args->argc += add->argc;
  186.     free(add->argv);
  187. }
  188.  
  189. typedef enum {
  190.     quote_none, quote_single, quote_double
  191. } quote_type;
  192.  
  193. typedef enum {
  194.     extract_normal, extract_test, extract_pattern
  195. } extract_type;
  196.  
  197. static void extract(char *buf, char *start, char *end,
  198.             quote_type type, extract_type extract)
  199. {
  200.     char *res = buf;
  201.  
  202.     switch (type) {
  203.     case quote_single:
  204.         if (extract != extract_test) {
  205.         buf[end - start] = '\0';
  206.         memcpy(buf, start, end - start);
  207.         } else
  208.         strcpy(buf, "a");      /* Things in quotes are never patterns */
  209.         break;
  210.  
  211.     case quote_none:
  212.         while (start < end) {
  213.         if (start[0] == '\\' && start[1]) {
  214.             start += 2;
  215.             /* Wildcard are escaped */
  216.             if (extract == extract_test) {
  217.             *res++ = 'a';
  218.             } else if (extract == extract_pattern) {
  219.             switch (start[-1]) {
  220.                 case '?':
  221.                 case '#':
  222.                 case '(':
  223.                 case ')':
  224.                 case '|':
  225.                 case '[':
  226.                 case ']':
  227.                 case '~':
  228.                 case '%':
  229.                 case '*':
  230.                 case '\'':
  231.                 *res++ = '\'';
  232.                 default:
  233.                 *res++ = start[-1];
  234.                 break;
  235.             }
  236.             } else {
  237.             *res++ = start[-1];
  238.             }
  239.         } else {
  240.             *res++ = *start++;
  241.         }
  242.         }
  243.         *res = '\0';
  244.         break;
  245.  
  246.     case quote_double:
  247.         while (start < end) {
  248.         if (start[0] == '*' && start[1]) {
  249.             start += 2;
  250.             switch (start[-1]) {
  251.             case 'n':
  252.                 *res++ = '\n';
  253.                 break;
  254.             case 'e':
  255.                 *res++ = '\x1b';
  256.                 break;
  257.             default:
  258.                 *res++ = start[-1];
  259.                 break;
  260.             }
  261.         } else
  262.             *res++ = *start++;
  263.         }
  264.         *res = '\0';
  265.         break;
  266.     }
  267. }
  268.  
  269. void __stdargs __main(char *line)
  270. /*  Effect: Call unix_main with wildcards in argc & argv expanded (like unix).
  271.  *  Also, do some early amiga initialisation for emacs.
  272.  */
  273. {
  274.     int ret;
  275.     struct args args, wildargs;
  276.     char *pattern, *arg_start, *arg_end, *arg;
  277.     quote_type arg_quoted;
  278.     long patlen = DEFPATLEN;
  279.     struct AnchorPath *anchor;
  280.     struct timeval now;
  281.  
  282.     if (SysBase->LibNode.lib_Version < 37)
  283.     _XCEXIT(20);
  284.  
  285.     stdin->_file = 0;
  286.     stdin->_flag = _IOREAD;
  287.     stdout->_file = 1;
  288.     stdout->_flag = _IOWRT | _IOLBF;
  289.     stderr->_file = 2;
  290.     stderr->_flag = _IOWRT | _IONBF;
  291.  
  292.     _us = (struct Process *) FindTask(0);
  293.     _odd_timer = _alloc_timer();
  294.     if (!_odd_timer)
  295.     _fail("Failed to create timer");
  296.     _odd_sig = _timer_sig(_odd_timer);
  297.     TimerBase = (struct Library *) _odd_timer->io->tr_node.io_Device;
  298.     GetSysTime(&now);
  299.     _startup_time = now.tv_secs;
  300.  
  301.     /* These use _startup_time, so must be here */
  302.     _init_fifo();
  303.     _init_signals();
  304.  
  305.     if (_us->pr_CLI)
  306.     _stack_size = ((struct CommandLineInterface *) BADDR(_us->pr_CLI))->cli_DefaultStack << 2;
  307.     else
  308.     _stack_size = _us->pr_StackSize;
  309.  
  310.     /* Make unix-like argc, argv (expand wildcards) */
  311.     if (!line[0]) {
  312.     /* Workbench, create argc & argv from files passed */
  313.     extern struct WBStartup *WBenchMsg;
  314.     int i;
  315.  
  316.     /* Initialise I/O. SAS C runtime provide us an input/output window */
  317.     BPTR winin = __ufbs->ufbfh;
  318.     BPTR winout = __ufbs->ufbnxt->ufbfh;
  319.     BPTR winerr = __ufbs->ufbnxt->ufbnxt->ufbfh;
  320.  
  321.     /* Give up if nothing is available */
  322.     if (!winin || !winout || !winerr)
  323.         _fail("No standard I/O");
  324.  
  325.     _init_unixio(winin, FALSE, winout, FALSE, winerr, FALSE);
  326.  
  327.     /* Make argc, argv from Workbench parameters */
  328.     make_argv(&args, WBenchMsg->sm_NumArgs);
  329.  
  330.     for (i = 0; i < WBenchMsg->sm_NumArgs; i++) {
  331.         char filename[256];
  332.  
  333.         if (NameFromLock(WBenchMsg->sm_ArgList[i].wa_Lock, filename, 256)) {
  334.         AddPart(filename, WBenchMsg->sm_ArgList[i].wa_Name, 256);
  335.         add_arg(&args, filename, TRUE);
  336.         }
  337.         /* else A parameter was lost, cry, cry, cry */
  338.     }
  339.     } else {
  340.     /* From CLI expand wildcards (with unix-like command line parsing) */
  341.     BPTR in, out, err;
  342.  
  343.     /* Initialise I/O. Copy CLI info provided by SAS/C runtime */
  344.     in = __ufbs->ufbfh;
  345.     out = __ufbs->ufbnxt->ufbfh;
  346.     if ((err = _us->pr_CES) == 0)
  347.         err = __ufbs->ufbnxt->ufbnxt->ufbfh;
  348.  
  349.     /* Give up if nothing is available */
  350.     if (!in || !out || !err)
  351.         _fail("No standard I/O");
  352.  
  353.     _init_unixio(in, FALSE, out, FALSE, err, FALSE);
  354.  
  355.     make_argv(&args, 1);
  356.  
  357.     anchor = _xmalloc(sizeof(struct AnchorPath) + NAMELEN);
  358.     anchor->ap_Strlen = NAMELEN;
  359.     pattern = _xmalloc(DEFPATLEN);
  360.     while (1) {
  361.         long new_patlen;
  362.         int wild;
  363.  
  364.         /* Skip white space */
  365.         while (isspace(*line))
  366.         line++;
  367.         if (!*line)
  368.         break;          /* End of command line */
  369.  
  370.         /* Extract next word */
  371.         /* Words in double quotes are handled AmigaDOS style
  372.          * (+ filename expansion) */
  373.         if (*line == '"') {
  374.         line++;
  375.         arg_start = line;
  376.         /* Find end of word */
  377.         while (*line && *line != '"') {
  378.             /* '*' is an escape character inside double quotes
  379.              * (AmigaDOS compatibility) */
  380.             if ((*line == '*') && line[1])
  381.             line++;
  382.             line++;
  383.         }
  384.         arg_end = line;
  385.         if (*line == '"')
  386.             line++;
  387.         arg_quoted = quote_double;
  388.         }
  389.         /* Words in single quotes are handled unix style */
  390.         else if (*line == '\'') {
  391.         line++;
  392.         arg_start = line;
  393.         /* Find end of word */
  394.         while (*line && *line != '\'')
  395.             line++;
  396.         arg_end = line;
  397.         if (*line == '\'')
  398.             line++;
  399.         arg_quoted = quote_single;
  400.         }
  401.         /* Unquoted words are handled unix style */
  402.         else {              /* Plain word */
  403.         arg_start = line;
  404.         /* Find end of word */
  405.         while (*line && !isspace(*line)) {
  406.             if (*line == '\\' && line[1])
  407.             line++;
  408.             line++;
  409.         }
  410.         arg_end = line;
  411.         arg_quoted = quote_none;
  412.         }
  413.         arg = _xmalloc(arg_end - arg_start + 1);
  414.         if (args.argc == 0) {       /* Command name is left untouched */
  415.         strncpy(arg, arg_start, arg_end - arg_start);
  416.         arg[arg_end - arg_start] = 0;
  417.         add_arg(&args, arg, FALSE);
  418.         } else {
  419.         new_patlen = (arg_end - arg_start) * 2 + 16;
  420.         if (new_patlen > patlen) {
  421.             free(pattern);
  422.             pattern = _xmalloc(new_patlen);
  423.             patlen = new_patlen;
  424.         }
  425.         extract(arg, arg_start, arg_end, arg_quoted, extract_test);
  426.         wild = ParsePattern(arg, pattern, patlen);
  427.         if (wild < 0) {
  428.             *arg_end = 0;
  429.             _fail("Invalid wildcard %s", arg_start);
  430.         }
  431.         if (!wild) {
  432.             extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  433.             add_arg(&args, arg, FALSE);
  434.         } else {
  435.             int none = TRUE;
  436.             long error;
  437.  
  438.             anchor->ap_Flags = anchor->ap_Reserved = anchor->ap_BreakBits = 0;
  439.             extract(arg, arg_start, arg_end, arg_quoted, extract_pattern);
  440.             make_argv(&wildargs, 16);
  441.             error = MatchFirst(arg, anchor);
  442.             while (!error) {
  443.             none = FALSE;
  444.             if (!safe_add_arg(&wildargs, anchor->ap_Buf, TRUE)) {
  445.                 error = ERROR_NO_FREE_STORE;
  446.                 break;
  447.             }
  448.             error = MatchNext(anchor);
  449.             }
  450.             MatchEnd(anchor);
  451.             if (error != ERROR_NO_MORE_ENTRIES)
  452.             _fail("Error expanding arguments");
  453.             if (none) {
  454.             extract(arg, arg_start, arg_end, arg_quoted, extract_normal);
  455.             add_arg(&args, arg, FALSE);
  456.             } else {
  457.             tqsort(wildargs.argv, wildargs.argc);
  458.             concat_args(&args, &wildargs);
  459.             free(arg);
  460.             }
  461.         }
  462.         }
  463.     }
  464.     free(pattern);
  465.     free(anchor);
  466.     }
  467.  
  468.     make_environ();
  469.  
  470.     if (!(_amiga_user.pw_name = __getenv("USER")))
  471.     _amiga_user.pw_name = "user";
  472.     if (!(_amiga_user.pw_gecos = __getenv("USERNAME")))
  473.     _amiga_user.pw_gecos = _amiga_user.pw_name;
  474.     if (!(_amiga_user.pw_dir = __getenv("HOME")))
  475.     _amiga_user.pw_dir = "s:";
  476.     if (!(_amiga_user.pw_shell = __getenv("SHELL")))
  477.     _amiga_user.pw_shell = "bin:sh";
  478.     if (!(_system_name = __getenv("HOSTNAME")))
  479.     _system_name = "amiga";
  480.  
  481.     ret = main(args.argc, args.argv, environ);
  482.     exit(ret);
  483. }
  484.